package context

import (
	"go-test/src/com/miao/common/logger"
	"go-test/src/com/miao/common/set"
	"go-test/src/com/miao/common/utils"
	"log"
	"net"
	"sync"
	"time"
)

type PacketHandler interface {
	Decode(buffer []byte, ctx *ChannelContext) (interface{}, []byte, error)
	Handler(packet interface{}, ctx *ChannelContext)
	Encode(packet interface{}, ctx *ChannelContext) []byte
}

type ServerListener interface {
	AfterConnected(ctx *ChannelContext)
	BeforeClose(ctx *ChannelContext)
}

/*用于管理所有的连接*/
type GroupContext struct {
	sync.RWMutex
	Timeout        int64
	Users          *Users
	Ids            *Ids
	Groups         *Groups
	Connections    *set.Set
	ServerListener ServerListener
	PacketHandler  PacketHandler
}

/*封装的连接*/
type ChannelContext struct {
	sync.RWMutex
	LatestTimeOfReceivedData int64
	Conn                     net.Conn
	GroupContext             *GroupContext
	UserId                   string
	Id                       string
	Group                    *set.Set //set装载类型string
	ReadChan                 chan interface{}
	SendChan                 chan interface{}
	Stat                     *ChannelStat
}

/*用于连接的状态参数调用*/
type ChannelStat struct {
	DecodeFailedCount       int
	LatestOfReceiveDataTime int64
	IsStop bool
}

func (groupContext *GroupContext) InitGroupContext() {
	groupContext.Ids = NewIds()
	groupContext.Groups = NewGroups()
	groupContext.Users = NewUsers()
	groupContext.Connections = set.New()
	//go groupContext.HandleHeartBeating()
}

func InitChannelContext(conn net.Conn, ctx *GroupContext) *ChannelContext {
	var u = utils.GenUUID()
	channelContext := new(ChannelContext)
	channelContext.GroupContext = ctx
	channelContext.Conn = conn
	channelContext.Id = u
	channelContext.Group = set.New()
	channelContext.ReadChan = make(chan interface{}, 1)
	channelContext.SendChan = make(chan interface{}, 1)
	ctx.Ids.Idsmap[u] = channelContext
	initChannelStat(channelContext)
	return channelContext
}

func initChannelStat(ctx *ChannelContext) {
	ctx.Stat = new(ChannelStat)
}

/*心跳检测*/
func (groupContext *GroupContext) HandleHeartBeating() {
	for true {
		time.Sleep(time.Millisecond * time.Duration(10000))
		func() {
			if groupContext.Timeout > 0 {
				connections := groupContext.Connections
				for i := range connections.List() {
					channelContext := connections.List()[i].(*ChannelContext)
					latestTime := channelContext.LatestTimeOfReceivedData
					interval := time.Now().Unix() - latestTime
					if interval > groupContext.Timeout {
						logger.Debugf("客户端%s已经%d ms没有发送消息了，采取关闭措施", channelContext.Conn.RemoteAddr().String(), interval)
						channelContext.Conn.Close()
					}
				}
			}
			defer func() {
				logger.Debugf("当前连接数%d", groupContext.Connections.Len())
				logger.Debugf("当前%v", groupContext.Users.usersmap)
			}()
		}()
	}
}

/*解码入口类，可以自定义解码协议*/
func (channel *ChannelContext) HandleDecode(handler PacketHandler, buffer []byte) []byte {
	return decode(handler, buffer, channel)
}

func decode(handler PacketHandler, buffer []byte, channel *ChannelContext) []byte {
	packet, buffer, err := handler.Decode(buffer, channel)
	if err != nil {
		log.Println(err.Error())
		channel.Conn.Close()
	}
	if packet == nil {
		count := channel.Stat.DecodeFailedCount + 1
		channel.Stat.DecodeFailedCount = count
		logger.Debugf("客户端%s本次解码失败，共失败%d次，参与解码字节长度%d", channel.Conn.RemoteAddr().String(), channel.Stat.DecodeFailedCount, len(buffer))
		if channel.Stat.DecodeFailedCount > 5 {
			logger.Debugf("连续解码失败超过5次，关闭客户端")
			channel.Conn.Close()
		}
		return buffer
	} else { //解码成功操作
		channel.Stat.DecodeFailedCount = 0
		//将packet传入chan
		utils.SafeSend(channel.ReadChan,packet)
		if len(buffer) > 0 {
			logger.Debugf("客户端%s组包后剩余数据长度%d", channel.Conn.RemoteAddr().String(), len(buffer))
			return decode(handler, buffer, channel)
		} else {
			//channel.TmpBuffer = make([]byte, 0)
			logger.Debugf("客户端%s组包数据刚好用完", channel.Conn.RemoteAddr().String())
			return make([]byte, 0)
		}
	}
}

func (channel *ChannelContext) ReadChannelTask(reader chan interface{}, handler PacketHandler) {

	for {
		select {
		case receivePacket,ok := <-reader:
			if ok {
				handler.Handler(receivePacket, channel)
			}else {
				return
			}
		}
	}
}

func (channel *ChannelContext) SendChannelTask(sender chan interface{}, handler PacketHandler) {
	for {
		select {
		case sendPacket,ok := <-sender:
			if ok {
				buffer := handler.Encode(sendPacket, channel)
				channel.Conn.Write(buffer)
			}else {
				return
			}
		}
	}
}
